/* ************************************
 * TreeGen
 * ************************************
 */

import controlP5.*;

Node testTree = null;
TreeMap testTreemap = null;
PFont nodeFont = null;

static final int DRAW_ICICLE = 1;
static final int DRAW_GRAPH = 2;
static final int DRAW_TREEMAP = 3;

static final int BUFFER_SIZE = 1024*1024;

static final int MAX_PERMUTATION = 40;
int saveCount = 13;
int loadCount = 13;

// graph mode
int drawMode = DRAW_GRAPH;

// graphical user interface
ControlP5 gui = null;
boolean gui_inited = false;
Slider depthSlider, rootMinSlider, rootMaxSlider, otherMinSlider, otherMaxSlider;

static final int GUI_DEPTH_SLIDER		= 1;
static final int GUI_ROOT_MIN			= 2;
static final int GUI_ROOT_MAX			= 3;
static final int GUI_OTHER_MIN			= 4;
static final int GUI_OTHER_MAX			= 5;


// tree generation parameters
int maxTreeDepth = 6;
int rootChildMin = 3;
int rootChildMax = 6;

int otherChildMin = 0;
int otherChildMax = 5;

void makeInterface()
{
	if (gui_inited) {
		return;
	}
	gui_inited = true;
	
	gui = new ControlP5( this );
	depthSlider = gui.addSlider("depth", 1, 10, maxTreeDepth, 20, 850, 100, 15);
	depthSlider.setId(GUI_DEPTH_SLIDER);
	
	rootMinSlider = gui.addSlider("root min", 0, 10, rootChildMin, 20, 870, 100, 15);
	rootMinSlider.setId(GUI_ROOT_MIN);
	
	rootMaxSlider = gui.addSlider("root max", 0, 10, rootChildMax, 20, 900, 100, 15);
	rootMaxSlider.setId(GUI_ROOT_MAX);

	otherMinSlider = gui.addSlider("other min", 0, 10, rootChildMin, 200, 870, 100, 15);
	otherMinSlider.setId(GUI_OTHER_MIN);
	
	otherMaxSlider = gui.addSlider("other max", 0, 10, rootChildMax, 200, 900, 100, 15);
	otherMaxSlider.setId(GUI_OTHER_MAX);
}


void saveTree( Node tree )
{
	String filename = dataPath("tree-" + (saveCount) + ".txt");
	String lispFilename = dataPath("tree-" + (saveCount) + ".lisp");
	
	saveCount++;
	
	CachedFileWriter output = new CachedFileWriter( filename, null );
	//CachedFileWriter outputLisp = new CachedFileWriter( lispFilename, null );
	
	writeTree( tree, output, 0 );
	//writeLispCode( tree, outputLisp );
	
	output.closeFile();
	//outputLisp.closeFile();	
	
	println("\tTree saved to: " + filename + ", Lisp code to: " + lispFilename );
}

Node loadTree()
{
	CachedFileReader input = null;
        
        while (input == null)
        {
          String filename = dataPath("trees/tree-" + loadCount + ".txt");
          input = new CachedFileReader( filename, null );
          if (!input.isReady()) {
            loadCount = 1;
            input = null;
          }
          else
          {
            println("\t\t -> Loaded tree " + "tree-" + loadCount);
            loadCount++;
          }
        } 
	
	// read from file
	Node newTree = readTree( input, null );
	input.closeFile();
	
	// layout
	layoutIcicle( newTree );
	layoutGraphNodes( newTree, 0, 0 );
	
	return newTree;
	
}

void setup()
{
	size( 2500, 1000 );
	smooth();
	
	makeInterface();
	
	// create tree
	testTree = makeNewTree( maxTreeDepth - 1 );
	testTreemap = new TreeMap( testTree );

	// setup font
	nodeFont = createFont("HelveticaBold", 16.0);
}
 
void draw()
{
	
	background (170);
	
	textFont( nodeFont );
	textAlign( CENTER, CENTER );
	
	fill(0);
	noFill();

	stroke(0);
	strokeWeight(1.5);
	
	pushMatrix();
	{
		translate( 30, 30 );
		switch (drawMode)
		{
		case DRAW_ICICLE:
			renderIcicle( testTree );
			break;
			
		case DRAW_GRAPH:
			renderGraph( testTree );
			break;
		
		case DRAW_TREEMAP:
			pushStyle();
				rectMode( CORNERS );
				testTreemap.draw( );
			popStyle();
			
			break;
		}
	}
	popMatrix();
	
}

void keyPressed()
{
	switch (key)
	{
	case ' ':
		println("New tree. Max depth: " + maxTreeDepth);
		testTree = makeNewTree( maxTreeDepth - 1 );
		testTreemap = new TreeMap(testTree);
		break;
	
	case 'i':
	case 'I':
		drawMode = DRAW_ICICLE;
		break;
		
	case 'g':
	case 'G':
		drawMode = DRAW_GRAPH;
		break;
		
	case 't':
	case 'T':
		drawMode = DRAW_TREEMAP;
		break;
	
	case 'r':
	case 'R':
		println("randomizing tree structure...");
		randomizeTree( testTree );
		testTreemap = new TreeMap(testTree);
		layout( testTree );
		
		break;
		
	case 's':
	case 'S':
		saveTree( testTree );
		break;
	
	case 'l':
	case 'L':
		testTree = loadTree ( );
		break;
	
	case 'x':
	case 'X':
		convertTXTToLisp("trees");
		break;
	}
}


// gui callbacks
// =============
public void controlEvent(ControlEvent theEvent)
{
	if (!gui_inited) {
		return;
	}
	int id = -1;
	
	try {
		
		id = theEvent.controller().id();
	}
	catch (Exception e)
	{
		return;
	}
	
	int val;
	
	switch (id)
	{
	case GUI_DEPTH_SLIDER:
		
		val = (int) depthSlider.value();
		maxTreeDepth = val;
		break;

	case GUI_ROOT_MIN:
		
		val = (int) rootMinSlider.value();
		rootChildMin = val;
		break;

	case GUI_ROOT_MAX:
		
		val = (int) rootMaxSlider.value();
		rootChildMax = val;
		break;

	case GUI_OTHER_MIN:
		
		val = (int) otherMinSlider.value();
		otherChildMin = val;
		break;

	case GUI_OTHER_MAX:
		
		val = (int) otherMaxSlider.value();
		otherChildMax = val;
		break;

	}
}
